home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / tcl / tcl70b2.lha / tcl7.0b2 / compat / strtod.c < prev    next >
C/C++ Source or Header  |  1993-07-12  |  7KB  |  274 lines

  1. /* 
  2.  * strtod.c --
  3.  *
  4.  *    Source code for the "strtod" library procedure.
  5.  *
  6.  * Copyright (c) 1988-1993 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Permission is hereby granted, without written agreement and without
  10.  * license or royalty fees, to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose, provided that the
  12.  * above copyright notice and the following two paragraphs appear in
  13.  * all copies of this software.
  14.  * 
  15.  * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR
  16.  * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT
  17.  * OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE UNIVERSITY OF
  18.  * CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  19.  *
  20.  * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
  21.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
  22.  * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS
  23.  * ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATION TO
  24.  * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /user6/ouster/tcl/compat/RCS/strtod.c,v 1.5 93/07/12 14:01:07 ouster Exp $ SPRITE (Berkeley)";
  29. #endif /* not lint */
  30.  
  31. #include <tcl.h>
  32. #ifdef NO_STDLIB_H
  33. #   include "compat/stdlib.h"
  34. #else
  35. #   include <stdlib.h>
  36. #endif
  37. #include <ctype.h>
  38.  
  39. #ifndef TRUE
  40. #define TRUE 1
  41. #define FALSE 0
  42. #endif
  43. #ifndef NULL
  44. #define NULL 0
  45. #endif
  46.  
  47. static int maxExponent = 511;    /* Largest possible base 10 exponent.  Any
  48.                  * exponent larger than this will already
  49.                  * produce underflow or overflow, so there's
  50.                  * no need to worry about additional digits.
  51.                  */
  52. static double powersOf10[] = {    /* Table giving binary powers of 10.  Entry */
  53.     10.,            /* is 10^2^i.  Used to convert decimal */
  54.     100.,            /* exponents into floating-point numbers. */
  55.     1.0e4,
  56.     1.0e8,
  57.     1.0e16,
  58.     1.0e32,
  59.     1.0e64,
  60.     1.0e128,
  61.     1.0e256
  62. };
  63.  
  64. /*
  65.  *----------------------------------------------------------------------
  66.  *
  67.  * strtod --
  68.  *
  69.  *    This procedure converts a floating-point number from an ASCII
  70.  *    decimal representation to internal double-precision format.
  71.  *
  72.  * Results:
  73.  *    The return value is the double-precision floating-point
  74.  *    representation of the characters in string.  If endPtr isn't
  75.  *    NULL, then *endPtr is filled in with the address of the
  76.  *    next character after the last one that was part of the
  77.  *    floating-point number.
  78.  *
  79.  * Side effects:
  80.  *    None.
  81.  *
  82.  *----------------------------------------------------------------------
  83.  */
  84.  
  85. double
  86. strtod(string, endPtr)
  87.     CONST char *string;        /* A decimal ASCII floating-point number,
  88.                  * optionally preceded by white space.
  89.                  * Must have form "-I.FE-X", where I is the
  90.                  * integer part of the mantissa, F is the
  91.                  * fractional part of the mantissa, and X
  92.                  * is the exponent.  Either of the signs
  93.                  * may be "+", "-", or omitted.  Either I
  94.                  * or F may be omitted, or both.  The decimal
  95.                  * point isn't necessary unless F is present.
  96.                  * The "E" may actually be an "e".  E and X
  97.                  * may both be omitted (but not just one).
  98.                  */
  99.     char **endPtr;        /* If non-NULL, store terminating character's
  100.                  * address here. */
  101. {
  102.     int sign, expSign = FALSE;
  103.     double fraction, dblExp, *d;
  104.     register CONST char *p;
  105.     register int c;
  106.     int exp = 0;        /* Exponent read from "EX" field. */
  107.     int fracExp = 0;        /* Exponent that derives from the fractional
  108.                  * part.  Under normal circumstatnces, it is
  109.                  * the negative of the number of digits in F.
  110.                  * However, if I is very long, the last digits
  111.                  * of I get dropped (otherwise a long I with a
  112.                  * large negative exponent could cause an
  113.                  * unnecessary overflow on I alone).  In this
  114.                  * case, fracExp is incremented one for each
  115.                  * dropped digit. */
  116.     int mantSize;        /* Number of digits in mantissa. */
  117.     int decPt;            /* Number of mantissa digits BEFORE decimal
  118.                  * point. */
  119.     CONST char *pExp;        /* Temporarily holds location of exponent
  120.                  * in string. */
  121.  
  122.     /*
  123.      * Strip off leading blanks and check for a sign.
  124.      */
  125.  
  126.     p = string;
  127.     while (isspace(*p)) {
  128.     p += 1;
  129.     }
  130.     if (*p == '-') {
  131.     sign = TRUE;
  132.     p += 1;
  133.     } else {
  134.     if (*p == '+') {
  135.         p += 1;
  136.     }
  137.     sign = FALSE;
  138.     }
  139.  
  140.     /*
  141.      * Count the number of digits in the mantissa (including the decimal
  142.      * point), and also locate the decimal point.
  143.      */
  144.  
  145.     decPt = -1;
  146.     for (mantSize = 0; ; mantSize += 1)
  147.     {
  148.     c = *p;
  149.     if (!isdigit(c)) {
  150.         if ((c != '.') || (decPt >= 0)) {
  151.         break;
  152.         }
  153.         decPt = mantSize;
  154.     }
  155.     p += 1;
  156.     }
  157.  
  158.     /*
  159.      * Now suck up the digits in the mantissa.  Use two integers to
  160.      * collect 9 digits each (this is faster than using floating-point).
  161.      * If the mantissa has more than 18 digits, ignore the extras, since
  162.      * they can't affect the value anyway.
  163.      */
  164.     
  165.     pExp  = p;
  166.     p -= mantSize;
  167.     if (decPt < 0) {
  168.     decPt = mantSize;
  169.     } else {
  170.     mantSize -= 1;            /* One of the digits was the point. */
  171.     }
  172.     if (mantSize > 18) {
  173.     fracExp = decPt - 18;
  174.     mantSize = 18;
  175.     } else {
  176.     fracExp = decPt - mantSize;
  177.     }
  178.     if (mantSize == 0) {
  179.     fraction = 0.0;
  180.     p = string;
  181.     goto done;
  182.     } else {
  183.     int frac1, frac2;
  184.     frac1 = 0;
  185.     for ( ; mantSize > 9; mantSize -= 1)
  186.     {
  187.         c = *p;
  188.         p += 1;
  189.         if (c == '.') {
  190.         c = *p;
  191.         p += 1;
  192.         }
  193.         frac1 = 10*frac1 + (c - '0');
  194.     }
  195.     frac2 = 0;
  196.     for (; mantSize > 0; mantSize -= 1)
  197.     {
  198.         c = *p;
  199.         p += 1;
  200.         if (c == '.') {
  201.         c = *p;
  202.         p += 1;
  203.         }
  204.         frac2 = 10*frac2 + (c - '0');
  205.     }
  206.     fraction = (1.0e9 * frac1) + frac2;
  207.     }
  208.  
  209.     /*
  210.      * Skim off the exponent.
  211.      */
  212.  
  213.     p = pExp;
  214.     if ((*p == 'E') || (*p == 'e')) {
  215.     p += 1;
  216.     if (*p == '-') {
  217.         expSign = TRUE;
  218.         p += 1;
  219.     } else {
  220.         if (*p == '+') {
  221.         p += 1;
  222.         }
  223.         expSign = FALSE;
  224.     }
  225.     while (isdigit(*p)) {
  226.         exp = exp * 10 + (*p - '0');
  227.         p += 1;
  228.     }
  229.     }
  230.     if (expSign) {
  231.     exp = fracExp - exp;
  232.     } else {
  233.     exp = fracExp + exp;
  234.     }
  235.  
  236.     /*
  237.      * Generate a floating-point number that represents the exponent.
  238.      * Do this by processing the exponent one bit at a time to combine
  239.      * many powers of 2 of 10. Then combine the exponent with the
  240.      * fraction.
  241.      */
  242.     
  243.     if (exp < 0) {
  244.     expSign = TRUE;
  245.     exp = -exp;
  246.     } else {
  247.     expSign = FALSE;
  248.     }
  249.     if (exp > maxExponent) {
  250.     exp = maxExponent;
  251.     }
  252.     dblExp = 1.0;
  253.     for (d = powersOf10; exp != 0; exp >>= 1, d += 1) {
  254.     if (exp & 01) {
  255.         dblExp *= *d;
  256.     }
  257.     }
  258.     if (expSign) {
  259.     fraction /= dblExp;
  260.     } else {
  261.     fraction *= dblExp;
  262.     }
  263.  
  264. done:
  265.     if (endPtr != NULL) {
  266.     *endPtr = (char *) p;
  267.     }
  268.  
  269.     if (sign) {
  270.     return -fraction;
  271.     }
  272.     return fraction;
  273. }
  274.